package com.yanjue.filter;

import com.alibaba.fastjson.JSONObject;
import com.yanjue.common.entity.User;
import com.yanjue.common.enums.HttpCodeEnum;
import com.yanjue.common.util.JwtUtil;
import com.yanjue.common.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import com.yanjue.config.WhiteListConfig;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Consumer;
import java.util.regex.Pattern;

/**
 * 请求拦截，验证身份
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private WhiteListConfig whiteListConfig;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.先获取白名单
        List<String> whitelist = whiteListConfig.getWhitelist();
        log.info("白名单数组 whiteList:{}=================================", whitelist);
        //2.获取请求
        ServerHttpRequest request = exchange.getRequest();
        //3.获取请求路径
        String path = request.getPath().toString();
        log.info("path路径:{}=====================", path);
        //4.使用路径匹配类，判断请求是否在白名单里
        AntPathMatcher pathMatcher = new AntPathMatcher();

        //主页接口、图书接口正则匹配
        boolean indexMatch = Pattern.matches("/index[^\\s]*", path);
        boolean bookMatch = Pattern.matches("/book/[^\\s]*", path);

        //判断是否匹配·匹配放行
        boolean b = whitelist.stream().anyMatch(url -> pathMatcher.match(url, path));
        log.info("白名单匹配是否匹配：{}", b);
        if (b || indexMatch || bookMatch) {
            return chain.filter(exchange);
        }

        //5.未匹配,验证身份信息,拿jwt
        //5.1.获取jwt
        String token = exchange.getRequest().getHeaders().getFirst("token");
        log.info("token:{}=========================", token);
        //5.2.解析
        Result<User> result = JwtUtil.validationToken(token);
        String[] segments = path.split("/");
        if (!whitelist.contains(segments[1])) {
            if (result.getCode() == HttpCodeEnum.OK.getCode()) {
                //认证成功
                User user = result.getData();
                log.info("user:{}===================", user);

                //5.3.追加请求头用户信息，方便后续访问用户数据
                Consumer<HttpHeaders> httpHeaders = httpHeader -> {
                    httpHeader.set("userId", user.getId().toString());
                    httpHeader.set("nickName", user.getNickName());
                };
                ServerHttpRequest serverHttpRequest = exchange.getRequest()
                        .mutate()
                        .headers(httpHeaders)
                        .build();
                exchange.mutate().request(serverHttpRequest).build();

                /* redisTemplate.opsForValue().set(LoginKeyPrefix.LOGIN_KEY+user.getId(),);*/

                return chain.filter(exchange);
            }

            log.info("认证失败==========================");
            //认证过期、失败，返回401
            ServerHttpResponse response = exchange.getResponse();
            log.info("response:{}========================", response);
            byte[] bits = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = response.bufferFactory().wrap(bits);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 指定编码，否则在浏览器中会中文乱码
            response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
            return response.writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 1;
    }

}
